package com.agent.membership.service;

import com.agent.common.constant.CommonConstants;
import com.agent.common.exception.BusinessException;
import com.agent.common.exception.ValidationException;
import com.agent.common.result.ResultCode;
import com.agent.common.utils.CreditCalculator;
import com.agent.common.utils.IdGenerator;
import com.agent.membership.dto.CreditOptions;
import com.agent.membership.dto.UpgradeResult;
import com.agent.membership.entity.CreditAccount;
import com.agent.membership.entity.CreditTransaction;
import com.agent.membership.entity.MembershipPlan;
import com.agent.membership.entity.MembershipSubscription;
import com.agent.membership.mapper.CreditAccountMapper;
import com.agent.membership.mapper.CreditTransactionMapper;
import com.agent.membership.mapper.MembershipPlanMapper;
import com.agent.membership.mapper.MembershipSubscriptionMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;

/**
 * 积分管理服务
 *
 * @author Jeff_Wan
 * @description 处理积分计算、扣除、发放等核心逻辑
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CreditService {
    private final CreditAccountMapper creditAccountMapper;
    private final CreditTransactionMapper creditTransactionMapper;
    private final MembershipSubscriptionMapper subscriptionMapper;
    private final MembershipPlanMapper membershipPlanMapper;
    private final IdGenerator idGenerator = IdGenerator.getInstance();

    /**
     * 初始化用户积分账户
     *
     * @param userId 用户ID
     */
    @Transactional
    public void initCreditAccount(Long userId) {
        // 检查是否已存在账户
        CreditAccount existingAccount = creditAccountMapper.selectByUserId(userId);
        if (existingAccount != null) {
            return;
        }

        // 创建新账户
        CreditAccount account = new CreditAccount();
        account.setId(idGenerator.nextId());
        account.setUserId(userId);
        account.setTotalCredits(0);
        account.setSubscriptionCredits(0);
        account.setBonusCredits(0);
        creditAccountMapper.insert(account);

        // 为新用户添加奖励积分
        addBonusCredits(userId, 10, "新用户注册奖励", null);
    }

    /**
     * 添加奖励积分
     *
     * @param userId   用户ID
     * @param amount   积分数量
     * @param source   来源描述
     * @param expireAt 过期时间(UTC)
     */
    @Transactional
    public void addBonusCredits(Long userId, Integer amount, String source, LocalDateTime expireAt) {
        // 获取账户
        CreditAccount account = creditAccountMapper.selectByUserId(userId);
        if (account == null) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }

        // 更新账户
        int updated = creditAccountMapper.addBonusCredits(userId, amount);

        if (updated == 0) {
            throw new OptimisticLockingFailureException("Concurrent update failure of points account");
        }

        // 记录交易
        recordTransaction(userId, "INCOME", "BONUS", amount, source,
                "奖励积分", null, expireAt);
    }

    /**
     * 扣除积分
     *
     * @param userId    用户ID
     * @param amount    积分数量
     * @param source    来源描述
     * @param relatedId 关联ID
     * @return 是否扣除成功
     */
    @Transactional
    public boolean deductCredits(Long userId, Integer amount, String source, Long relatedId) {
        // 获取账户
        CreditAccount account = creditAccountMapper.selectByUserId(userId);
        if (account == null) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }
        // 检查积分是否足够
        if (account.getTotalCredits() < amount) {
            return false;
        }

        // 优先扣除奖励积分
        int deductFromBonus = Math.min(account.getBonusCredits(), amount);
        int remaining = amount - deductFromBonus;

        if (deductFromBonus > 0) {
            creditAccountMapper.deductBonusCredits(userId, deductFromBonus);
            recordTransaction(userId, "EXPENSE", "BONUS", deductFromBonus, source,
                    "扣除奖励积分", relatedId, null);
        }

        if (remaining > 0) {
            creditAccountMapper.deductSubscriptionCredits(userId, remaining);
            recordTransaction(userId, "EXPENSE", "SUBSCRIPTION", remaining, source,
                    "扣除订阅积分", relatedId, null);
        }

        // 更新总积分
        creditAccountMapper.deductTotalCredits(userId, amount);
        return true;
    }

    /**
     * 记录积分交易
     *
     * @param userId          用户ID
     * @param transactionType 交易类型
     * @param creditType      积分类型
     * @param amount          数量
     * @param source          来源
     * @param description     描述
     * @param relatedId       关联ID
     * @param expireAt        过期时间(UTC)
     */
    private void recordTransaction(Long userId, String transactionType, String creditType,
                                   Integer amount, String source, String description,
                                   Long relatedId, LocalDateTime expireAt) {
        // 获取账户
        CreditAccount account = creditAccountMapper.selectByUserId(userId);
        if (account == null) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }

        // 创建交易记录
        CreditTransaction transaction = new CreditTransaction();
        transaction.setId(idGenerator.nextId());
        transaction.setAccountId(account.getId());
        transaction.setUserId(userId);
        transaction.setTransactionType(transactionType);
        transaction.setCreditType(creditType);
        transaction.setAmount(amount);
        transaction.setSource(source);
        transaction.setDescription(description);
        transaction.setRelatedId(relatedId);
        transaction.setExpireAt(expireAt);
        transaction.setExpired(false);

        creditTransactionMapper.insert(transaction);
    }

    /**
     * 获取用户积分详情
     *
     * @param userId 用户ID
     * @return 积分账户对象
     */
    public CreditAccount getCreditAccount(Long userId) {
        return creditAccountMapper.selectByUserId(userId);
    }

    /**
     * 计算任务所需积分
     *
     * @param options 选项参数
     * @return 所需积分
     */
    public int calculateRequiredCredits(CreditOptions options) {
        String model = options.getModel();

        // 视频模型积分计算
        if (model.contains("Seedance") || model.contains("Veo")) {
            if (options.getDuration() == null || options.getResolution() == null) {
                throw new ValidationException(ResultCode.INVALID_PARAMETERS, "The video generation parameters are incomplete");
            }
            return CreditCalculator.calculateVideoCredits(model,
                    options.getDuration(), options.getResolution());
        }
        // 图片模型积分计算
        else if (model.contains("GPT-Image") || model.contains("Flux Pro")) {
            if (options.getQuantity() == null) {
                throw new ValidationException(ResultCode.INVALID_PARAMETERS, "The image generation parameters are incomplete");
            }
            return CreditCalculator.calculateImageCredits(model, options.getQuantity());
        }
        // 不支持模型
        else {
            throw new ValidationException(ResultCode.MODEL_NOT_SUPPORTED);
        }
    }

    /**
     * 发放订阅积分 (带重试机制)
     */
    @Transactional
    @Retryable(value = OptimisticLockingFailureException.class,
            maxAttempts = 3,
            backoff = @Backoff(delay = 200))
    public void issueSubscriptionCredits() {
        LocalDate today = LocalDate.now(ZoneOffset.UTC);
        List<MembershipSubscription> activeMemberships = subscriptionMapper.findActiveMemberships(today);

        for (MembershipSubscription membership : activeMemberships) {
            // 检查本月是否已发放 (UTC时间)
            if (membership.getLastCreditIssuedDate() != null) {
                LocalDate lastIssueDate = membership.getLastCreditIssuedDate()
                        .atZone(ZoneOffset.UTC)
                        .toLocalDate();

                if (lastIssueDate.getMonth() == today.getMonth() &&
                        lastIssueDate.getYear() == today.getYear()) {
                    continue;
                }
            }

            // 获取套餐配置
            MembershipPlan plan = membershipPlanMapper.findByPlanAndSubscription(
                    membership.getPlanType(), membership.getSubscriptionType());

            if (plan != null) {
                // 发放积分
                CreditAccount account = creditAccountMapper.selectByUserId(membership.getUserId());
                int updated = creditAccountMapper.addSubscriptionCredits(
                        membership.getUserId(),
                        plan.getCreditsPerPeriod());

                if (updated == 0) {
                    throw new OptimisticLockingFailureException("Concurrent update failure of points account");
                }

                // 记录交易
                String source = membership.getPlanType() + "_" +
                        membership.getSubscriptionType() + "_积分发放";

                LocalDateTime expireAt = LocalDateTime.now(ZoneOffset.UTC)
                        .plusMonths(1)
                        .withDayOfMonth(1)
                        .minusDays(1);

                recordTransaction(membership.getUserId(), "INCOME", "SUBSCRIPTION",
                        plan.getCreditsPerPeriod(), source, "订阅积分发放", null, expireAt);

                // 更新最后发放日期
                membership.setLastCreditIssuedDate(LocalDateTime.now(ZoneOffset.UTC));
                subscriptionMapper.updateById(membership);
            }
        }
    }

    /**
     * 计算升级费用
     *
     * @param userId              用户ID
     * @param newPlanType         新套餐类型
     * @param newSubscriptionType 新订阅类型
     * @return 升级费用
     */
    public BigDecimal calculateUpgradeCost(Long userId, String newPlanType, String newSubscriptionType) {
        MembershipSubscription current = subscriptionMapper.selectByUserId(userId);
        if (current == null) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }

        // 检查升级条件
        if (!canUpgrade(current.getPlanType(), newPlanType)) {
            throw new BusinessException(ResultCode.MEMBERSHIP_UPGRADE_FAILED);
        }

        // 计算剩余积分价值
        BigDecimal creditValue = calculateCreditValue(current);

        // 获取新套餐价格
        MembershipPlan newPlan = membershipPlanMapper.findByPlanAndSubscription(
                newPlanType, newSubscriptionType);
        if (newPlan == null) {
            throw new BusinessException(ResultCode.INVALID_SUBSCRIPTION_PLAN);
        }

        // 计算实际费用
        return newPlan.getPrice().subtract(creditValue).max(BigDecimal.ZERO);
    }

    /**
     * 会员升级逻辑
     *
     * @param userId              用户ID
     * @param newPlanType         新套餐类型
     * @param newSubscriptionType 新订阅类型
     */
    @Transactional
    public UpgradeResult upgradeMembership(Long userId, String newPlanType, String newSubscriptionType) {
        MembershipSubscription currentMembership = subscriptionMapper.selectByUserId(userId);
        if (currentMembership == null) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }

        // 检查升级条件
        if (!canUpgrade(currentMembership.getPlanType(), newPlanType)) {
            throw new BusinessException(ResultCode.MEMBERSHIP_UPGRADE_FAILED, "Unable to upgrade to the specified package");
        }

        // 获取新套餐配置
        MembershipPlan newPlan = membershipPlanMapper.findByPlanAndSubscription(
                newPlanType, newSubscriptionType);
        if (newPlan == null) {
            throw new BusinessException(ResultCode.INVALID_SUBSCRIPTION_PLAN);
        }

        // 计算剩余积分价值
        BigDecimal creditValue = calculateCreditValue(currentMembership);

        // 计算新套餐费用（第一周期）
        BigDecimal newPrice = newPlan.getPrice().subtract(creditValue);
        if (newPrice.compareTo(BigDecimal.ZERO) < 0) {
            newPrice = BigDecimal.ZERO;
        }

        // 创建新订阅
        MembershipSubscription newMembership = new MembershipSubscription();
        newMembership.setId(idGenerator.nextId());
        newMembership.setUserId(userId);
        newMembership.setPlanType(newPlanType);
        newMembership.setSubscriptionType(newSubscriptionType);
        newMembership.setStartDate(LocalDateTime.now());

        // 计算结束日期
        if (newSubscriptionType.equals(CommonConstants.SUBSCRIPTION_YEARLY)) {
            newMembership.setExpiryDate(LocalDateTime.now().plusYears(1));
        } else {
            newMembership.setExpiryDate(LocalDateTime.now().plusMonths(1));
        }

        newMembership.setAutoRenew(true);
        subscriptionMapper.insert(newMembership);

        // 返回支付信息（实际支付服务处理）
        return new UpgradeResult(newPrice, newPlan, creditValue);
    }

    /**
     * 计算剩余积分价值
     */
    private BigDecimal calculateCreditValue(MembershipSubscription membership) {
        CreditAccount account = creditAccountMapper.selectByUserId(membership.getUserId());
        if (account == null) {
            return BigDecimal.ZERO;
        }

        // 获取当前套餐配置
        MembershipPlan currentPlan = membershipPlanMapper.findByPlanAndSubscription(
                membership.getPlanType(), membership.getSubscriptionType());
        if (currentPlan == null) {
            return BigDecimal.ZERO;
        }

        // 计算积分单价
        BigDecimal creditPrice = currentPlan.getPrice()
                .divide(BigDecimal.valueOf(currentPlan.getCreditsPerPeriod()), 2, RoundingMode.HALF_UP);

        // 计算剩余积分价值
        return creditPrice.multiply(BigDecimal.valueOf(account.getTotalCredits()));
    }

    /**
     * 检查是否可以升级
     */
    private boolean canUpgrade(String currentPlan, String newPlan) {
        // 免费用户可以直接升级
        if (currentPlan.equals(CommonConstants.MEMBER_FREE)) {
            return true;
        }

        // 比较套餐等级
        return getPlanLevel(newPlan) > getPlanLevel(currentPlan);
    }

    /**
     * 获取套餐等级
     */
    private int getPlanLevel(String planType) {
        switch (planType) {
            case CommonConstants.MEMBER_BASIC:
                return 1;
            case CommonConstants.MEMBER_PRO:
                return 2;
            case CommonConstants.MEMBER_MAX:
                return 3;
            default:
                return 0; // FREE
        }
    }

    /**
     * 处理过期积分
     */
    @Transactional
    public void expireCredits() {
        LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
        List<CreditTransaction> expiredCredits = creditTransactionMapper
                .findExpiredTransactions(now);

        for (CreditTransaction credit : expiredCredits) {
            try {
                // 更新账户
                CreditAccount account = creditAccountMapper.selectById(credit.getAccountId());
                int updated = creditAccountMapper.deductTotalCredits(
                        account.getUserId(),
                        credit.getAmount());

                if (updated > 0) {
                    // 更新积分类型数量
                    if ("BONUS".equals(credit.getCreditType())) {
                        creditAccountMapper.deductBonusCredits(
                                account.getUserId(), credit.getAmount());
                    } else {
                        creditAccountMapper.deductSubscriptionCredits(
                                account.getUserId(), credit.getAmount());
                    }

                    // 标记为已过期
                    credit.setExpired(true);
                    creditTransactionMapper.updateById(credit);

                    log.info("过期积分处理成功: user={}, amount={}",
                            credit.getUserId(), credit.getAmount());
                }
            } catch (Exception e) {
                log.error("过期积分处理失败: {}", credit.getId(), e);
            }
        }
    }
}